<template>
  <!-- 通知 -->
  <div class="mr-5 relative">
    <i @mouseenter="noticeMouseEnterHandler"
       @mouseleave="noticeMouseLeaveHandler"
       ref="noticeRef"
       class="pi pi-bell p-text-secondary relative"
       style="font-size: 2rem; color: #8B5CF6; transition: color .3s linear;">
      <Badge v-show="(systemCount + detailCount + chatCount) > 0"
             class="absolute m-0 p-0 notice__header__badge"
             :value="systemCount + detailCount + chatCount > 99 ? '99+' : systemCount + detailCount + chatCount"></Badge>
    </i>
    <!-- 通知内容 -->
    <div class="absolute user__notice flex"
         @mouseenter="noticeMouseEnterShowHandler"
         @mouseleave="noticeMouseLeaveHandler"
         ref="userNoticeRef"
         style="width: 300px; right: -100px; border-radius: 10px; overflow-y: scroll; z-index: 10;">
      <!-- 内容 container -->
      <div style="width: 100%;">
        <!-- 父级包含 -->
        <div class="m-0">
          <!-- 筛选框 -->
          <div class="col-12 p-0 m-0 sticky" style="background-color: white; z-index:4; top: 0;">
            <div class="relative">
              <!-- 筛选消息类型 -->
              <div class="col-12 p-1">
                <div class="flex">
                  <!-- 每次移动95px -->
                  <div class="notice__type" @click="noticeType(0)">
                    全部
                    <Badge v-show="(systemCount + detailCount + chatCount) > 0"
                           class="notice__badge"
                           :value="systemCount + detailCount + chatCount > 99 ? '99+' : systemCount + detailCount + chatCount"></Badge>
                  </div>
                  <div class="notice__type" @click="noticeType(1)">
                    系统
                    <Badge v-show="systemCount > 0"
                           class="notice__badge"
                           :value="systemCount"></Badge>
                  </div>
                  <div class="notice__type" @click="noticeType(2)">
                    文章
                    <Badge v-show="detailCount > 0"
                           class="notice__badge"
                           :value="detailCount"></Badge>
                  </div>
                  <div class="notice__type" @click="noticeType(3)">
                    聊天
                    <Badge v-show="chatCount > 0"
                           class="notice__badge"
                           :value="chatCount"></Badge>
                  </div>
                </div>
              </div>
              <!-- 滑动条 -->
              <div class="col-12 p-0" style="background-color: white; z-index:4; height: 5px;">
                <div class="col-3 p-0 m-1 flex justify-content-center absolute">
                  <div ref="moveRef"
                       style="height: 3px; background-color: blue; width: 80%; transition: transform .3s;"></div>
                </div>
              </div>
            </div>
          </div>
          <!-- 通知内容 -->
          <div class="relative">
            <!-- 通知 -->
            <div v-for="(item, index) in noticeMessages"
                 :key="index"
                 class="col-12 flex p-2 pt-3" style="width: 100%;">
              <!-- 头像 -->
              <div class="flex" style="width: 20%;">
                <ImgTextAvatar shape="circle"
                               :image="item.avatar"
                               :label="item.nickname"
                               height="40px" width="40px"></ImgTextAvatar>
              </div>
              <div class="flex grid justify-content-start ml-1" style="width: 80%;">
                <!--                color: rgb(51,141,255);-->
                <div class="col-12 text-left"
                     style="font-size: 13px; padding: 5px;"
                     :style="`${item.type === -4 ? 'color: rgb(51,141,255);' : ''}`">
                  <!-- 系统通知 -->
                  {{ item.nickname }}
                  <div style="font-size: 6px;"
                       :style="`${item.type === -4 ? 'color: rgb(237,66,66);' : ''}`">
                    {{ item.typeStr }}
                    <!-- 系统消息 -->
                  </div>
                </div>
                <div class="col-12 text-left m-text-overflow-ellipsis-4"
                     v-html="item.content"
                     style="font-size: 14px;  color: rgb(24, 25, 28); padding: 5px; max-height: 80px;">
                </div>
                <div class="col-12" style="font-size: 12px; color: rgb(148,153,160)">
                  <!--                  1分钟前-->
                  {{ item.noticeTime }}
                </div>
              </div>
            </div>
            <!-- empty -->
            <div class="grid m-0 p-2" v-if="noticeMessages.length === 0">
              <div class="flex justify-content-center col-12">
                <svg viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" width="128" height="128">
                  <path
                      d="M512 0C229.261369 0 0 229.261369 0 512c0 282.738631 229.261369 512 512 512 282.738631 0 512-229.261369 512-512C1024 229.261369 794.738631 0 512 0L512 0zM512 999.82009c-269.049475 0-487.948026-218.898551-487.948026-487.948026 0-269.049475 218.898551-487.948026 487.948026-487.948026 269.049475 0 487.948026 218.898551 487.948026 487.948026C999.82009 781.049475 781.049475 999.82009 512 999.82009L512 999.82009zM512 999.82009"
                      fill="#bfbfbf"></path>
                  <path
                      d="M223.632184 430.888556c0 16.375812 6.78061 32.623688 18.294853 44.265867 11.642179 11.642179 27.890055 18.294853 44.265867 18.294853 16.375812 0 32.623688-6.78061 44.265867-18.294853 11.642179-11.642179 18.294853-27.890055 18.294853-44.265867 0-16.375812-6.78061-32.751624-18.294853-44.265867-11.642179-11.642179-27.890055-18.294853-44.265867-18.294853-16.375812 0-32.751624 6.78061-44.265867 18.294853C230.412794 398.264868 223.632184 414.512744 223.632184 430.888556L223.632184 430.888556zM223.632184 430.888556"
                      fill="#bfbfbf"></path>
                  <path
                      d="M674.606697 424.61969c0 16.503748 6.78061 33.007496 18.550725 44.777611 11.642179 11.642179 28.145927 18.550725 44.649675 18.550725 16.503748 0 33.007496-6.78061 44.777611-18.550725 11.770115-11.770115 18.550725-28.145927 18.550725-44.777611 0-16.503748-6.78061-33.007496-18.550725-44.777611-11.642179-11.642179-28.145927-18.550725-44.777611-18.550725-16.503748 0-33.007496 6.78061-44.649675 18.550725C681.387306 391.612194 674.606697 408.115942 674.606697 424.61969L674.606697 424.61969zM674.606697 424.61969"
                      fill="#bfbfbf"></path>
                  <path
                      d="M385.471264 275.702149c-4.605697-11.642179-17.3993-17.527236-28.785607-13.049475l-153.77911 60.257871c-11.386307 4.477761-16.75962 17.527236-12.281859 29.041479l4.093953 10.490755c4.605697 11.642179 17.3993 17.527236 28.785607 13.049475l153.77911-60.257871c11.386307-4.477761 16.75962-17.527236 12.281859-29.169415L385.471264 275.702149 385.471264 275.702149zM385.471264 275.702149"
                      fill="#bfbfbf"></path>
                  <path
                      d="M830.688656 318.816592l-156.465767-52.965517c-11.514243-3.838081-24.17991 2.558721-28.145927 14.328836l-3.582209 10.746627c-3.966017 11.898051 2.046977 24.563718 13.561219 28.529735l156.465767 52.965517c11.514243 3.966017 24.051974-2.558721 28.145927-14.328836l3.582209-10.746627C848.343828 335.448276 842.202899 322.654673 830.688656 318.816592L830.688656 318.816592zM830.688656 318.816592"
                      fill="#bfbfbf"></path>
                  <path
                      d="M696.995502 663.604198c-6.268866-9.083458-18.550725-11.514243-27.378311-5.501249l-120.515742 82.902549c-8.827586 6.14093-11.002499 18.422789-4.733633 27.634183l5.629185 8.187906c6.268866 9.083458 18.550725 11.514243 27.378311 5.501249l120.515742-82.902549c8.827586-6.14093 11.002499-18.422789 4.733633-27.634183L696.995502 663.604198 696.995502 663.604198zM696.995502 663.604198"
                      fill="#bfbfbf"></path>
                </svg>
              </div>
              <div class="flex justify-content-center col-12">
                还没有任何通知哦😟‍
              </div>
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>

  <div class="mr-2" style="min-height: 64px !important; min-width: 64px !important;">
    <span id="userButtonSelected"
          class="mr-9 p-button-raised p-button-text p-0"
          style="z-index: 5;"
          v-if="loginStatus">
         <SpeedDial :model="userButtonSelected" direction="down" @click="speedDialClick"/>
    </span>
    <Button v-else ref="loginBtn" label="登录" @click="loginShow = true;" class="mr-2 mt-2 p-component p-button-text"/>
    <!-- 登录弹窗 -->
    <Dialog v-model:visible="loginShow"
            header="登录/注册"
            modal
            class="loginDialog login__reg__dialog"
            @hide="loginDialogHideHandler"
            :style="{ width: '50vw' }">
      <TabMenu :model="loginTabs.selected" @tab-change="loginTabsChangeHandler"/>
      <div id="loginOrReg"
           class="loginOrReg pt-3"
           style="width: 50vw !important">
        <transition name="loginTransition"
                    appear
                    v-on:before-enter="tabAnimateEnterBeforeActiveHandler"
                    v-on:before-leave="tabAnimateLeaveBeforeActiveHandler">
          <div class="absolute login" style="overflow: hidden !important;" v-if="loginTabs.active === 0">
            <!-- 用户名 -->
            <div class="field">
              <label for="username">用户名</label>
              <div class="p-inputgroup">
                <span class="p-inputgroup-addon">
                  <i class="pi pi-user"></i>
                </span>
                <InputText id="username"
                           placeholder="输入用户名"
                           v-model="loginForm.username"/>
              </div>
            </div>
            <!-- 密码 -->
            <div class="field">
              <label for="password">密码</label>
              <div class="p-inputgroup">
                <span class="p-inputgroup-addon">
                  <i class="pi pi-lock"></i>
                </span>
                <Password id="password"
                          :feedback="false"
                          placeholder="输入密码"
                          v-model="loginForm.password"/>
              </div>
            </div>
            <!-- 保存登录信息 -->
            <div class="field flex align-items-center flex-wrap m-fl pl-1">
              <InputSwitch v-model="saveUserLoginInfo"/>
              <span class="flex align-items-center justify-content-center ml-2">是否保存用户信息</span>
            </div>
            <div class="clear-both"></div>
            <!-- 操作按钮 -->
            <div class="field">
              <Button class="m-fr" @click="loginHandler">登录</Button>
            </div>
          </div>
        </transition>
        <transition name="registerTransition"
                    v-on:before-enter="tabAnimateEnterBeforeActiveHandler"
                    v-on:before-leave="tabAnimateLeaveBeforeActiveHandler"
                    v-on:after-enter="tabAnimateEnterAfterActiveHandler">
          <div class="relative register" v-if="loginTabs.active === 1">
            <!-- 用户名 -->
            <div class="field">
              <div class="grid">
                <div class="col-12">
                  <label for="username">用户名</label>
                  <div class="p-inputgroup">
                      <span class="p-inputgroup-addon">
                        <i class="pi pi-user"></i>
                      </span>
                    <InputText class="p-inputtext-sm"
                               :class="{'p-invalid': !validate.username}"
                               id="username"
                               placeholder="输入用户名"
                               maxlength="10"
                               v-model="registerForm.username"
                               v-tooltip.focus="'用户名长度 x 需要满足3<=x<=10'"/>
                  </div>
                </div>
                <div class="col-12" v-if="!validate.username">
                  <InlineMessage>用户名长度不符合要求，请确保长度在 3~10 之内</InlineMessage>
                </div>
              </div>
            </div>
            <!-- 密码 -->
            <div class="field">
              <div class="grid">
                <div class="col-12">
                  <label for="password">密码</label>
                  <div class="p-inputgroup">
                  <span class="p-inputgroup-addon">
                    <i class="pi pi-lock"></i>
                  </span>
                    <Password class="w-full p-inputtext-sm"
                              :class="{'p-invalid': !validate.password}"
                              id="password"
                              toggleMask
                              :feedback="false"
                              placeholder="输入密码"
                              v-model="registerForm.password"
                              v-tooltip.focus="'密码长度最起码 8 位'"/>
                  </div>
                </div>
                <div class="col-12" v-if="!validate.password">
                  <InlineMessage>密码长度最少要有 8 位</InlineMessage>
                </div>
              </div>
            </div>
            <!-- 确认密码 -->
            <div class="field">
              <div class="grid">
                <div class="col-12">
                  <label for="truthPassword">确认密码</label>
                  <div class="p-inputgroup">
                    <span class="p-inputgroup-addon">
                      <i class="pi pi-lock-open"></i>
                    </span>
                    <InputText id="truthPassword"
                               class="p-inputtext-sm"
                               :class="{'p-invalid': !validate.truthPassword}"
                               placeholder="请再次确认密码"
                               v-model="registerForm.truthPassword"/>
                  </div>
                </div>
                <div class="col-12" v-if="!validate.truthPassword">
                  <InlineMessage>确认密码与密码不相同，请重新输入</InlineMessage>
                </div>
              </div>
            </div>
            <!-- email -->
            <div class="field">
              <div class="grid">
                <div class="col-12">
                  <label for="email">电子邮箱</label>
                  <div class="p-inputgroup">
                    <span class="p-inputgroup-addon">
                      <i class="pi pi-envelope"></i>
                    </span>
                    <InputText id="email"
                               class="p-inputtext-sm"
                               :class="{'p-invalid': !validate.email}"
                               placeholder="邮箱信箱账号"
                               v-model="registerForm.emailPrefix"/>
                    <span class="p-inputgroup-addon">
                      @
                    </span>
                    <InputText id="email"
                               class="p-inputtext-sm"
                               :class="{'p-invalid': !validate.email}"
                               placeholder="邮箱服务器"
                               v-model="registerForm.emailSuffix"/>
                    <span class="p-inputgroup-addon">.com</span>
                    <Button :loading="emailCodeLoading"
                            :label="emailBtnText"
                            :disabled="emailBtnDisabled"
                            class="p-button-danger"
                            @click="sendEmailCode"/>
                  </div>
                </div>
                <div class="col-12" v-if="!validate.email">
                  <InlineMessage>电子邮箱不符合规范</InlineMessage>
                </div>
              </div>
            </div>
            <!-- 验证码 -->
            <div class="field">
              <div class="grid">
                <div class="col-12">
                  <label for="emailCode">验证码</label>
                  <div class="p-inputgroup">
                  <span class="p-inputgroup-addon">
                    <i class="pi pi-key"></i>
                  </span>
                    <InputText id="emailCode"
                               class="p-inputtext-sm"
                               :class="{'p-invalid': !validate.emailCode}"
                               maxlength="6"
                               placeholder="输入email验证码"
                               v-model="registerForm.code"/>
                  </div>
                </div>
                <div class="col-12" v-if="!validate.emailCode">
                  <InlineMessage>验证码不符合规范</InlineMessage>
                </div>
              </div>
            </div>
            <!-- 操作按钮 -->
            <div class="field">
              <Button class="m-fr"
                      :disabled="!openRegisterBtn"
                      @click="userRegisterHandler">
                注册
              </Button>
            </div>
          </div>
        </transition>
      </div>
    </Dialog>
  </div>
</template>

<script lang="ts" setup>
/** JS */
import {Ref, ref, reactive, watch, inject, onMounted, nextTick, defineExpose} from 'vue';
import Cache from '@/utils/Cache';
import {useRouter} from 'vue-router';
import UserStoreImpl from '@/interface/user/store/UserStore';
import SocketMessageStore from '@/interface/websocket/store/SocketMessageStore';
import {LoginForm, RegisterForm, UserMsg} from '@/interface/user/entity/UserEntityInterface';
import {encrypt, getCurrentTimestamp} from '@/utils/TimestampEncryption';
import {UserService} from '@/utils/ApiRequest';
import {Message, MessageTypes, NoticeMessage} from '@/interface/websocket/entity/SocketMessage';
/** 组件 */
import InputSwitch from 'primevue/inputswitch';
import Dialog from 'primevue/dialog';
import Password from 'primevue/password';
import TabMenu from 'primevue/tabmenu';
import InlineMessage from 'primevue/inlinemessage';
import Badge from 'primevue/badge';
import SpeedDial from 'primevue/speeddial';
import toast from "@/utils/Toast";
import {Websocket} from "@/utils/Webscoket";
import ImgTextAvatar from '@/components/avatar/ImgTextAvatar.vue';

/**
 * 注册校验接口
 */
interface RegisterValidations {
  username: boolean,
  password: boolean,
  truthPassword: boolean,
  email: boolean,
  emailCode: boolean,
  validate?: () => boolean
}


/**
 * 判断 str 是否为邮箱
 * @param str 字符串
 */
function isEmail(str: string) {
  return /^(\w+)(\.\w+)*@(\w+)(\.\w+)*.(\w+)$/i.test(str)
}

const userStore = new UserStoreImpl(),
    socketStore = new SocketMessageStore(),
    router = useRouter(),
    reload: (() => (void | undefined)) | undefined = inject('reload'),
    userService = new UserService(),
    cache = new Cache(),
    websocket: Websocket | undefined = inject('websocket'),
    showChatDialog: (() => (void | undefined)) | undefined = inject('showChatDialog'),
    messages: Array<(event) => void> | undefined = inject('messages');

/**  用户按钮的选项 */
const userButtonSelected = ref([
  {
    label: '登出',
    icon: 'pi pi-sign-out',
    command: () => {
      logOutHandler();
    }
  },
  {
    label: '个人中心',
    icon: 'pi pi-user',
    command: () => {
      router.push({
        path: '/centre'
      })
    }
  },
  {
    label: '聊天室',
    icon: 'pi pi-comment',
    command: () => {
      if (showChatDialog) {
        showChatDialog();
      }
    }
  }
]);
/** 修复挡住其他元素的问题 */
const speedDialClick = (ev: PointerEvent) => {
  let path = ev.composedPath();
  for (let eventTarget of path) {
    if ((eventTarget as HTMLElement).classList.contains('p-speeddial-direction-down')) {
      let element = eventTarget as HTMLElement;
      if (element.classList.contains('p-speeddial-opened')) {
        element.style.zIndex = '0';
      } else {
        element.style.zIndex = '1';
      }
      break;
    }
  }
}
/** 登录表单、状态、消息等数据 */
let loginShow = ref(false),
    // 登录信息
    loginSaveInfo = reactive(cache.get('loginInfo')),
    // login tabs
    loginTabs = reactive({
      active: 0,
      selected: [
        {
          label: '登录'
        },
        {
          label: '注册'
        }
      ]
    }),
    // tab 动画
    tabAnimate = reactive({
      enter: 'animate__animated animate__fadeIn',
      out: 'animate__animated animate__fadeOut'
    }),
    // 注册表单
    registerForm: RegisterForm = reactive({
      username: '',
      password: '',
      truthPassword: '',
      email: '',
      emailPrefix: '',
      emailSuffix: '',
      code: ''
    }),
    // 登录表单
    loginForm: LoginForm = reactive({
      username: loginSaveInfo ? loginSaveInfo.username : '',
      password: loginSaveInfo ? loginSaveInfo.password : ''
    }),
    // 登录状态
    loginStatus = ref(userStore.getLoginStatus()),
    // 用户消息
    userMsg: Ref<UserMsg> = ref(userStore.getUserMsg()),
    // 开放注册按钮
    openRegisterBtn = ref(false),
    // 是否保存用户登录信息
    saveUserLoginInfo = ref(!!loginSaveInfo);
/** 注册校验结果 */
let validate: RegisterValidations = reactive({
  username: true,
  password: true,
  truthPassword: true,
  email: true,
  emailCode: true,
  validate: () => {
    // 遍历 validate 判断是否全部验证通过
    for (let key in validate) {
      if (key === 'validate') continue;
      if (!validate[key as keyof RegisterValidations]) {
        return false;
      }
    }
    return true;
  }
});
/** 监听注册表单进行跟踪校验 */
watch(registerForm, (newForm) => {
  // 用户名去空格以及校验
  if (newForm.username !== '') {
    if (newForm.username.indexOf(' ') !== -1) {
      registerForm.username = registerForm.username.trim();
    }
    validate.username = newForm.username.length > 3;
  }
  // 密码校验
  if (newForm.password !== '') {
    validate.password = newForm.password.length >= 8;
  }
  // 确认密码校验
  if (newForm.truthPassword !== '') {
    validate.truthPassword = newForm.truthPassword === newForm.password;
  }
  // 校验电子邮箱
  if (registerForm.emailPrefix?.trim() !== '' && registerForm.emailSuffix?.trim() !== '') {
    registerForm.email = registerForm.emailPrefix + '@' + registerForm.emailSuffix + '.com';
    validate.email = isEmail(registerForm.email);
  }
  // 校验验证码并清除空格
  if (registerForm.code !== '') {
    if (registerForm.code.indexOf('') !== -1) {
      registerForm.code = registerForm.code.trim();
    }
    validate.emailCode = registerForm.code.length === 6;
  }
  // 遍历注册表单判断是否有空数据，如果有空数据则直接跳出且不开放注册。
  for (let key in newForm) {
    if (newForm[key as keyof RegisterForm] === '') {
      openRegisterBtn.value = false;
      return;
    }
    openRegisterBtn.value = validate.validate ? validate.validate() : false;
  }

});
/** navigate 动画 */
const tabAnimateEnterBeforeActiveHandler = (el: HTMLDivElement) => {
      // 进入之前
      let enterClass = tabAnimate.enter,
          leaveClass = tabAnimate.out,
          elClass = el.className;
      if (elClass.indexOf(leaveClass) !== -1) {
        elClass = elClass.replace(leaveClass, enterClass);
      } else if (elClass.indexOf(enterClass) === -1) {
        elClass = elClass + ' ' + enterClass;
      }
      el.className = elClass;
    },
    tabAnimateLeaveBeforeActiveHandler = (el: HTMLDivElement) => {
      // 离开之前
      let enterClass = tabAnimate.enter,
          leaveClass = tabAnimate.out,
          elClass = el.className;
      if (elClass.indexOf(enterClass) !== -1) {
        elClass = elClass.replace(enterClass, leaveClass);
      } else if (elClass.indexOf(leaveClass) === -1) {
        elClass = elClass + ' ' + leaveClass;
      }
      el.className = elClass;
    },
    tabAnimateEnterAfterActiveHandler = () => {
      // 进入之后由于注册表单比较长，因此可能会有高度溢出的现象，所以此处添加滚动条【默认全局滚动条为隐藏】
      const parentNode = document.getElementById('loginOrReg')?.parentNode as HTMLElement;
      // 单独对高度溢出时显示滚动条
      parentNode.setAttribute('style', 'overflow-y: auto !important; overflow-x: hidden !important');
    }
/** login tabs 切换操作 */
const loginTabsChangeHandler = (e: any) => {
      let {index} = e;
      if (loginTabs.active !== index) {
        const lor = document.getElementById('loginOrReg'),
            parentNode = lor?.parentNode as HTMLElement,
            tabNode = parentNode.children[0].children[0];
        // 修改动画
        if (loginTabs.active === 1) {
          tabAnimate.enter = 'animate__animated animate__fadeInRight';
          tabAnimate.out = 'animate__animated animate__fadeOutLeft';
          // 手动更替激活样式
          tabNode.children[0].className = tabNode.children[0].className + ' p-highlight';
          if (tabNode.children[1].className.indexOf('p-highlight') !== -1) {
            tabNode.children[1].className = tabNode.children[1].className.replace(' p-highlight', '');
          }
          // 取消高度溢出的滚动条
          parentNode.removeAttribute('style');
          if (parentNode.className.indexOf(' register-content') !== -1) {
            parentNode.className = parentNode.className.replace(' register-content', ' login-content');
          } else {
            parentNode.className += 'login-content';
          }
        } else if (loginTabs.active === 0) {
          tabAnimate.enter = 'animate__animated animate__fadeInLeft';
          tabAnimate.out = 'animate__animated animate__fadeOutRight';
          // 手动更替激活样式
          tabNode.children[1].className = tabNode.children[1].className + ' p-highlight';
          if (tabNode.children[0].className.indexOf('p-highlight') !== -1) {
            tabNode.children[0].className = tabNode.children[0].className.replace(' p-highlight', '');
          }
          if (parentNode.className.indexOf('register-content') !== -1) {
            parentNode.className = parentNode.className.replace(' login-content', ' register-content');
          } else {
            parentNode.className += ' register-content';
          }
        }
        // 修改动画后改变 index
        loginTabs.active = index;
      }
    },
    // loginDialog 隐藏操作/
    loginDialogHideHandler = () => {
      loginTabs.active = 0;
      tabAnimate.enter = 'animate__animated animate__fadeIn';
      tabAnimate.out = 'animate__animated animate__fadeOut';
      let rKey: keyof RegisterForm;
      for (rKey in registerForm) {
        registerForm[rKey] = '';
      }
      let lKey: keyof LoginForm;
      for (lKey in loginForm) {
        loginForm[lKey] = ''
      }
    }
/** 注册、登录、登出操作 */
const loginHandler = async () => {
      let result: UserMsg = await userStore.login(loginForm);
      // 更新用户信息
      if (userStore.validateEmpty(result)) {
        Object.assign(userMsg.value, result);
        loginStatus.value = true;
        if (websocket) {
          websocket.send({
            type: MessageTypes.UserLogin,
            context: userMsg.value
          })
        }
      }
      loginShow.value = false;
      // 是否保存用户登录信息
      await saveUserLoginInfoHandler();
      if (reload) {
        reload();
      }
    },
    // 用户登出
    logOutHandler = async () => {
      await userStore.logOut();
      loginStatus.value = false;
      if (websocket) {
        websocket.send({
          type: MessageTypes.UserLogOut,
          context: userMsg.value
        })
      }
      if (reload) {
        reload();
      }
    },
    // 用户注册
    userRegisterHandler = async () => {
      await userService.register(registerForm);
      // 注册成功后将账号密码存储至登录表单并且进行自动切换
      loginForm.username = registerForm.username;
      loginForm.password = registerForm.password;
      loginTabsChangeHandler({index: 0})
    };
/** 保存用户信息至浏览器 */
const saveUserLoginInfoHandler = async () => {
  if (saveUserLoginInfo.value) {
    cache.set('loginInfo', {username: loginForm.username, password: loginForm.password});
  } else {
    cache.remove('loginInfo');
  }
};
/** 邮箱操作 */
const emailCodeLoading = ref(false),
    emailBtnDisabled = ref(false),
    emailBtnText = ref('发送验证码'),
    emailCodeCountdown = ref(90),
    /** 获取邮箱注册验证码 */
    sendEmailCode = async () => {
      emailCodeLoading.value = true;
      emailBtnDisabled.value = true;
      const timestamp: string = getCurrentTimestamp(), email = encrypt(registerForm.email as string, timestamp);
      // 发送邮箱
      let res = await userService.sendEmailCode(email as string, timestamp)
          .catch(() => emailBtnDisabled.value = false)
          .finally(() => emailCodeLoading.value = false);
      if (res.code === 0) {
        toast.success('发送成功', `请留意 ${registerForm.email} 最新的邮箱信息，如果没有请到回收站查找或重新发送。`, 3000);
        // 冷却倒数，90S 冷却
        let countdown = setInterval(() => {
          emailCodeCountdown.value -= 1;
          emailBtnText.value = emailCodeCountdown.value + '';
        }, 1000);
        // 90 秒冷却时间，冷却后变回初始数据
        setTimeout(() => {
          emailBtnDisabled.value = false;
          emailBtnText.value = '发送验证码';
          emailCodeCountdown.value = 90;
          window.clearInterval(countdown);
        }, 90000);
      }
    };

/** 用户通知 */
const moveUnit = 70,
    moveMode = ref(0),
    moveRef = ref(null),
    userNoticeRef = ref(null), noticeRef = ref(null), loginBtn = ref(null);
let notices = socketStore.getNotices();
const noticeMessages: Ref<NoticeMessage[]> = ref([]),
    /** 全部消息 */
    allNoticeMessages: Ref<NoticeMessage[]> = ref(notices.allNoticeMessages),
    /** 系统消息 */
    systemNoticeMessages: Ref<NoticeMessage[]> = ref(notices.systemNoticeMessages),
    /** 文章消息 */
    detailNoticeMessages: Ref<NoticeMessage[]> = ref(notices.detailNoticeMessages),
    /** 聊天消息 */
    chatNoticeMessages: Ref<NoticeMessage[]> = ref(notices.chatNoticeMessages);
watch(systemNoticeMessages, (n) => {
  systemCount.value = n.length;
})
watch(detailNoticeMessages, (n) => {
  detailCount.value = n.length;
})
watch(chatNoticeMessages, (n) => {
  chatCount.value = n.length;
})
/**
 * 系统通知数量
 */
const systemCount: Ref<number> = ref(systemNoticeMessages.value.length),
    /**
     * 文章通知
     */
    detailCount: Ref<number> = ref(detailNoticeMessages.value.length),
    /**
     * 私聊通知
     */
    chatCount: Ref<number> = ref(chatNoticeMessages.value.length);
/**
 * 消息框的监听
 */
let noticeTimeout: ReturnType<typeof setTimeout> = setTimeout(() => {
});

/**
 * notice 消息栏显示
 */
function noticeShow() {
  if (moveMode.value === 0) {
    noticeMessages.value = allNoticeMessages.value;
  } else if (moveMode.value === 1) {
    noticeMessages.value = systemNoticeMessages.value;
  } else if (moveMode.value === 2) {
    noticeMessages.value = detailNoticeMessages.value;
  } else if (moveMode.value === 3) {
    noticeMessages.value = chatNoticeMessages.value;
  }
  window.clearTimeout(noticeTimeout);
  if (userNoticeRef.value) {
    let element = userNoticeRef.value as HTMLElement;
    element.style.maxHeight = '390px';
    element.style.maxWidth = '300px';
  }
}

/**
 * notice 消息栏隐藏
 */
function noticeHide() {
  if (userNoticeRef.value) {
    let element = userNoticeRef.value as HTMLElement;
    element.style.maxHeight = '0px';
    element.style.maxWidth = '0px';
  }
}


/** 动态消息渲染 */
const saveNoticeMessages = () => {
  let notices = {
    allNoticeMessages: allNoticeMessages.value,
    systemNoticeMessages: systemNoticeMessages.value,
    chatNoticeMessages: chatNoticeMessages.value,
    detailNoticeMessages: detailNoticeMessages.value
  }
  socketStore.saveNotices(notices);
}
const notice = (type: number, msg: any, noticeTime?: string, unshift?: boolean) => {
  switch (type) {
      // 文章通知
    case MessageTypes.DetailNotice: {
      let notice: NoticeMessage = {
        type: type,
        avatar: msg.avatar,
        nickname: msg.author,
        content: `我发布了一篇<a href='/logger/#/detail/${msg.id}'>《${msg.title}》</a>的文章，你有兴趣就去看看吧！~(●'◡'●)`,
        typeStr: '文章消息',
        noticeTime: ''
      };
      if (noticeTime === undefined) {
        notice.noticeTime = '1分钟前'
      } else {
        notice.noticeTime = noticeTime;
      }
      if (unshift) {
        allNoticeMessages.value.unshift(notice);
        detailNoticeMessages.value.unshift(notice);
      } else {
        allNoticeMessages.value.push(notice);
        detailNoticeMessages.value.push(notice);
      }
      saveNoticeMessages();
      detailCount.value += 1;
      break;
    }
    case MessageTypes.PrivateChat: {
      if (noticeTime != undefined) {
        let notice: NoticeMessage = {
          type: type,
          avatar: msg.from.avatar,
          nickname: msg.from.nickname,
          content: msg.text,
          typeStr: '私聊消息',
          noticeTime: noticeTime
        };
        // 类型为聊天信息时，text 必须不存在
        allNoticeMessages.value.push(notice);
        chatNoticeMessages.value.push(notice);
        chatCount.value += 1;
      }
      break;
    }
  }
}
messages?.push(async (res) => {
  let result: Message[] | Message = JSON.parse(res.data);
  if (result instanceof Array) {
    for (let message of result) {
      // 内容上下文必须存在
      notice(message.type, JSON.parse(message.context), message.noticeTime);
    }
  } else {
    // 单通知
    notice(result.type, JSON.parse(result.context), result.noticeTime, true);
  }
});
/** 显示通知栏 */
const noticeMouseEnterHandler = () => {
      noticeShow();
    },
    /** 移出生成对象时 */
    noticeMouseLeaveHandler = () => {
      noticeTimeout = setTimeout(() => {
        noticeHide();
      }, 200);
    },
    /** 移入消息框时 */
    noticeMouseEnterShowHandler = () => {
      window.clearTimeout(noticeTimeout);
    },
    /** 滑块移动计算 */
    noticeType = (type: number) => {
      let move = moveUnit * type;
      moveMode.value = type;
      if (type === 0) {
        noticeMessages.value = allNoticeMessages.value;
      } else if (type === 1) {
        noticeMessages.value = systemNoticeMessages.value;
      } else if (type === 2) {
        noticeMessages.value = detailNoticeMessages.value;
      } else if (type === 3) {
        noticeMessages.value = chatNoticeMessages.value;
      }
      if (moveRef.value) {
        let element = moveRef.value as HTMLElement;
        element.style.transform = `translate(${move}px)`;
      }

    };


onMounted(() => {
  // 判断是否读取用户信息
  if (saveUserLoginInfo.value) {
    loginForm.username = cache.get('loginInfo').username;
    loginForm.password = cache.get('loginInfo').password;
  } else {
    loginForm.username = '';
    loginForm.password = '';
  }
  // 动态加载用户按钮
  let doc: HTMLElement | null = document.getElementById('userButtonSelected');
  nextTick(() => {
    if (doc && loginStatus.value) {
      let speeddial: HTMLElement = doc.children[0] as HTMLElement;
      speeddial.style.zIndex = '0';
      let child: HTMLElement = speeddial.children[0] as HTMLElement;
      child.style.transition = 'all .3s';
      let height = child.clientHeight, width = child.clientWidth;
      child.removeChild(child.children[0]);
      child.removeChild(child.children[0]);
      if (userMsg.value.avatar) {
        const imgDoc = document.createElement('img');
        // imgDoc.classList.add('lg:w-4rem', 'md:w-3rem', 'sm:w-3rem', 'ssm:w-3rem');
        imgDoc.setAttribute('style', `border-radius:50%; height: ${height}px !important; width: ${width}px !important;`)
        imgDoc.setAttribute('src', userMsg.value.avatar);
        child.append(imgDoc);
      } else {
        const divDoc = document.createElement('div'), childDoc = document.createElement('span');
        childDoc.setAttribute('class', 'p-avatar-text');
        childDoc.innerText = userMsg.value.nickname.substring(0, 1).toUpperCase();
        // imgDoc.classList.add('lg:w-4rem', 'md:w-3rem', 'sm:w-3rem', 'ssm:w-3rem');
        divDoc.setAttribute('style', `border-radius:50%; height: ${height}px !important; width: ${width}px !important;background-color: #8B5CF6;`)
        divDoc.setAttribute('class', 'p-avatar p-component');
        divDoc.append(childDoc);
        child.appendChild(divDoc)
      }
    }
  });
})

defineExpose({
  noticeRef,
  userNoticeRef,
  loginBtn
})
</script>

<style lang="less" scoped>
.p-inputgroup {
  color: red !important;

  &:focus {
    border-color: red !important;
  }
}
</style>